/*
 * UMLSynch plugin for Eclipse
 * http://umlsynch.googlecode.com
 *
 * Copyright 2008-2010, Evgeny Alexeyev
 * Licensed under the EPL - v1.0
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */

package com.googlecode.umlsynch.EclipseOperationServer;

import java.io.*;
import java.net.*;

import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;

import com.googlecode.umlsynch.eclipse.rpc.Debug.TEclipseDebug;

public class TEclipseOperationServerDispatcher { 
	IEclipseOperationServer classImplementation;
	
	ServerSocket server; 
	ObjectOutputStream outObjStream;
	ObjectInputStream inObjStream;
	Job  operation = null;
	private boolean flag = true;

	TEclipseDebug debug = new TEclipseDebug("Disp");

	// 64k buffer for input stream  
	byte buf[] = new byte[64*1024];

	public TEclipseOperationServerDispatcher(IEclipseOperationServer ClassImplementation) {
		debug.Note("TEclipseOperationServerDispatcher");

		classImplementation = ClassImplementation;
		outObjStream = null;
		inObjStream = null;

		debug.Note("Thread class" );
		operation = new Job("VPSDE") 
		{

			protected IStatus run(IProgressMonitor monitor)   
			{
				do {
					try {
						server = new ServerSocket(3128, 0, InetAddress.getByName("localhost"));
					}
					catch(Exception e) {
						debug.Note("init error: "+e);
						return Status.OK_STATUS;
					} 

					try {
						// accept client socket 
						do
						{
							debug.Note("accept socket");
							Socket s = server.accept();
							outObjStream = new ObjectOutputStream(s.getOutputStream());
							inObjStream = new ObjectInputStream(s.getInputStream());

							debug.Note("read function");
							String data = (String)inObjStream.readObject();
							debug.Note("read function:" + data);

							if (data.equals("GetClassRelations")) {
								GetClassRelations(s);
							}
							else if (data.equals("UpdateClassData")) {
								UpdateClassData(s);
							}
							else if (data.equals("OpenClassWithEditor")) {
								OpenClassWithEditor(s);
							}
							else if (data.equals("SearchTextPattern")) {
								SearchTextPattern(s);
							}
							else if (data.equals("FindClassByName")) {
								FindClassByName(s);
							}
							else if (data.equals("FindValueByName")) {
								FindValueByName(s);
							}
							else if (data.equals("FindValueByType")) {
								FindValueByType(s);
							}
							else if (data.equals("OpenMethodImplementation")) {
								OpenMethodImplementation(s);
							}

							else if (data.equals("CloseEclipseConnection")) {
								s.close();
								break;
							}			
							s.close();
						} while (true);
						// close access for client socket
					}
					catch(Exception e) 
					{
						debug.Note("catch exception " + e.getLocalizedMessage() + e.getCause() );
						StackTraceElement[] st = e.getStackTrace();
						for (int i =0; i <st.length; ++i) {
							if (st[i].getFileName() != null)
								debug.Note(st[i].getFileName() + st[i].getLineNumber());
						}
					}
					try {
						server.close();
					} catch (IOException e) {
						debug.Error("Exception: " + e.getLocalizedMessage());
					}
				} while (flag == true);
				
				return Status.OK_STATUS;
				
			}
			
		};
		debug.Note("run workbench job" );
		// run client-server communication 
		//operation.start();
		operation.setPriority(Job.INTERACTIVE);
	    operation.schedule();

	}
	public void GetClassRelations(Socket s) {
    /* VPSDEClassDescription[] GetClassRelations(
		 		VPSDEClassDescription desc, 
		 		String relationType,
		 		String[] searchRestrictions); */
		
		VPSDEClassDescription[] result = null;
		VPSDEClassDescription desc = null;
		String relationType = null;
		String[] searchRestrictions = null;

		int readData;  
		String data;
		
		try {
			data = (String)inObjStream.readObject();
			if (data.equals("VPSDEClassDescription")) {

				desc = (VPSDEClassDescription) inObjStream.readObject();
			}

			data = (String)inObjStream.readObject();
			if (data.equals("String")) {

				relationType = (String) inObjStream.readObject();
			}
			
			data = (String)inObjStream.readObject();
			if (data.equals("String[]")) {

				searchRestrictions = (String[]) inObjStream.readObject();
			}			
			
			result = 
				classImplementation.GetClassRelations(desc, relationType, searchRestrictions);

			// Serialization do not support array storage and null pointer storage
			if (result != null) {
				outObjStream.writeObject(new String("VPSDEClassDescription[]"));
				outObjStream.writeObject(result);
			} else {
				outObjStream.writeObject(new String("VPSDEClassDescription[]Null"));
			}
		} catch (IOException ex ){

		} catch (ClassNotFoundException e) {
		}	
	} 

	public void UpdateClassData(Socket s) {
		VPSDEClassDescription UpClass_local = null;
		VPSDEClassDescription ClassName_local = null;

		// ------------ Read something from socket  
		String data;  
		try
		{


			data = (String)inObjStream.readObject();
			if (data.equals("VPSDEClassDescription")) {

				ClassName_local = (VPSDEClassDescription) inObjStream.readObject();
			}
			UpClass_local = classImplementation.UpdateClassData(ClassName_local);
			
			if (UpClass_local == null) {
				outObjStream.writeObject(new String("VPSDEClassDescriptionNull"));
			} else {
				outObjStream.writeObject(new String("VPSDEClassDescription"));
				outObjStream.writeObject(UpClass_local);
			}
			
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}	
	} //end of UpdateClassData

	public void OpenClassWithEditor(Socket s) {
		VPSDEClassDescription desc = null;

		String data;  
		try {
			data = (String)inObjStream.readObject();
			if (data.equals("VPSDEClassDescription")) {

				desc = (VPSDEClassDescription) inObjStream.readObject();
			}
			classImplementation.OpenClassWithEditor(desc);
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}	
	} //end of OpenClassWithEditor
	
	private void SearchTextPattern(Socket s) {
		VPSDESearchQueryDescription desc = null;

		// Read query object
		String data;  
		try	{
			data = (String)inObjStream.readObject();
			if (data.equals("VPSDESearchQueryDescription")) {

				desc = (VPSDESearchQueryDescription) inObjStream.readObject();
			}
			classImplementation.SearchTextPattern(desc);
		} catch (IOException ex ){
			debug.Note("IOException " + ex.getMessage());
		} catch (ClassNotFoundException e) {
			debug.Note("ClassNotFoundException " + e.getMessage());
		}		
	}
	
	
	public void FindClassByName(Socket s) {
		try {
			String data = (String)inObjStream.readObject();
			String[] searchPaths = null;
			if (data.equals("String[]")) {
				searchPaths = (String[]) inObjStream.readObject();
			}

			String searchNamePattern = null;
			if (data.equals("String")) {
				searchNamePattern = (String) inObjStream.readObject();
			}

			VPSDEClassDescription[] result = classImplementation.FindClassByName(searchPaths, searchNamePattern);
			
			if (result == null) {
				outObjStream.writeObject(new String("VPSDEClassDescription[]Null"));
			} else {
				outObjStream.writeObject(new String("VPSDEClassDescription[]"));
				outObjStream.writeObject(result);
			}
			
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}	

	}


	public void FindValueByName(Socket s) {
		// 	public String FindValueInitializationByName(String sourceFile, String namePattern) {

		try {
			String data = (String)inObjStream.readObject();
			String sourceFile = null;
			if (data.equals("String")) {
				sourceFile = (String) inObjStream.readObject();
			}

			String namePattern = null;
			if (data.equals("String")) {
				namePattern = (String) inObjStream.readObject();
			}

			String result = classImplementation.FindValueByName(sourceFile, namePattern);
			
			if (result == null) {
				outObjStream.writeObject(new String("StringNull"));
			} else {
				outObjStream.writeObject(new String("String"));
				outObjStream.writeObject(result);
			}
			
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}	
	}

	public void FindValueByType(Socket s) {
		// 	public String FindValueInitializationByName(String sourceFile, String namePattern) {

		try {
			String data = (String)inObjStream.readObject();
			String sourceFile = null;
			if (data.equals("String")) {
				sourceFile = (String) inObjStream.readObject();
			}

			String namePattern = null;
			if (data.equals("String")) {
				namePattern = (String) inObjStream.readObject();
			}

			String result = classImplementation.FindValueByType(sourceFile, namePattern);
			
			if (result == null) {
				outObjStream.writeObject(new String("StringNull"));
			} else {
				outObjStream.writeObject(new String("String"));
				outObjStream.writeObject(result);
			}
			
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}	
	}

	
	public void OpenMethodImplementation(Socket s) {
        //	public void OpenMethodImplementation(VPSDEClassDescription className, String methodName)
		try {
			String data = (String)inObjStream.readObject();
			VPSDEClassDescription className = null;
			if (data.equals("VPSDEClassDescription")) {
				className = (VPSDEClassDescription) inObjStream.readObject();
			}
			
			data = (String)inObjStream.readObject();
			String methodName = null;
			if (data.equals("String")) {
				methodName = (String) inObjStream.readObject();
			}
			
			data = (String)inObjStream.readObject();
			String Desc = null;
			if (data.equals("String")) {
				Desc = (String) inObjStream.readObject();
			}

			classImplementation.OpenMethodImplementation(className, methodName, Desc);
			
		} catch (IOException ex ){
		} catch (ClassNotFoundException e) {
		}		
	}
	public void Reset() {
		
		
	}

}  

